﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Net.NetworkInformation;
using PServiceBus.Core.Runtime;

namespace PServiceBus.WebSocket {
    internal class FlashPolicyServer {

        const int BUFFER_SIZE = 4096, FLASH_POLICY_SERVER_PORT = 843;

        static string _policyFile;
        static TcpListener _listener;
        static CancellationTokenSource _token = new CancellationTokenSource();

        static FlashPolicyServer() {
            ShellHelper.NetShAddTCPFirewall("PServiceBusFlashPolicyServer", FLASH_POLICY_SERVER_PORT);
            Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
            using (var stream = new FileStream("flashpolicy.xml", FileMode.Open))
            using (var reader = new StreamReader(stream))
                _policyFile = string.Format("{0}\0", reader.ReadToEnd());
        }

        public static void Start() {

            var properties = IPGlobalProperties.GetIPGlobalProperties();
            var tcpEndPoints = properties.GetActiveTcpListeners();

            if (tcpEndPoints.Any(x => x.Port == FLASH_POLICY_SERVER_PORT)) return;

            Task.Factory.StartNew(() => {
                _listener = new TcpListener(IPAddress.Any, FLASH_POLICY_SERVER_PORT);
                _listener.Start();

                while (!_token.IsCancellationRequested)
                    Task.Factory.StartNew(Handle, _listener.AcceptTcpClient())
                        .ContinueWith(_ => _.Exception.ToString(), TaskContinuationOptions.OnlyOnFaulted);
                
            }, _token.Token)
            .ContinueWith(t => t.Exception.ToString(), TaskContinuationOptions.OnlyOnFaulted);
        }

        private static void Handle(object obj) {
            var client = obj as TcpClient;
            var s = client.GetStream();

            var buffer = new byte[BUFFER_SIZE];

            int read = s.Read(buffer, 0, BUFFER_SIZE);

            if (read > 0) {
                var message = Encoding.ASCII.GetString(buffer, 0, read);
                if (message == "<policy-file-request/>\0") {
                    var data = Encoding.ASCII.GetBytes(_policyFile);
                    s.Write(data, 0, data.Length);
                    s.Flush();
                }
            };

            client.Close();
        }

        public static void Stop() {
            try {
                if (_listener != null) _listener.Stop();
                _token.Cancel();
            } catch { }
        }
    }
}
